/*
 * Copyright (c) 2018-2999 北京小象智慧信息科技有限公司 All rights reserved.
 *
 * https://www.xiaoxiangai.com/
 *
 * 未经允许，不可做商业用途！
 *
 * 版权所有，侵权必究！
 */

package com.yami.shop.admin.security;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.yami.shop.bean.enums.SmsType;
import com.yami.shop.common.util.Json;
import com.yami.shop.common.util.RedisUtil;
import com.yami.shop.security.constants.SecurityConstants;
import com.yami.shop.security.exception.BadCredentialsExceptionBase;
import com.yami.shop.security.exception.ImageCodeNotMatchExceptionBase;
import com.yami.shop.security.exception.UsernameNotFoundExceptionBase;
import com.yami.shop.security.provider.AuthenticationTokenParser;
import com.yami.shop.security.service.YamiUserDetailsService;
import com.yami.shop.service.ShopDetailService;
import com.yami.shop.service.SmsLogService;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * 小程序登陆：此时principal为code
 *       post:http://127.0.0.1:8086/login
 *       {principal:code}
 * 管理员登陆：
 *       post: http://127.0.0.1:8086/login
 *       {principal:username,credentials:password}
 */
@Component
public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    private YamiUserDetailsService yamiUserDetailsService;

    private PasswordEncoder passwordEncoder;

    @Autowired
    private ShopDetailService shopDetailService;

    @Autowired
    private SmsLogService smsLogService;



    @Autowired
    public LoginAuthenticationFilter(YamiUserDetailsService yamiUserDetailsService, PasswordEncoder passwordEncoder) {
        super("/login");
        this.yamiUserDetailsService = yamiUserDetailsService;
        this.passwordEncoder = passwordEncoder;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (!ServletUtil.METHOD_POST.equals(request.getMethod())) {
            throw new AuthenticationServiceException(
                    "Authentication method not supported: " + request.getMethod());
        }
        String requestBody = getStringFromStream(request);

        if (StrUtil.isBlank(requestBody)) {
            throw new AuthenticationServiceException("无法获取输入信息");
        }
        AdminAuthenticationToken adminAuthenticationToken  =  Json.parseObject(requestBody, AdminAuthenticationToken.class);
        String username = adminAuthenticationToken.getPrincipal() == null ? "NONE_PROVIDED" : adminAuthenticationToken.getName();
        String loginType = adminAuthenticationToken.getLoginType();
        AdminAuthenticationToken result = null;
        if("1".equals(loginType)) {
            UserDetails user = yamiUserDetailsService.loadUserByUsername(username);
            String kaptchaKey = SecurityConstants.SPRING_SECURITY_RESTFUL_IMAGE_CODE + adminAuthenticationToken.getSessionUUID();

            String kaptcha = RedisUtil.get(kaptchaKey);

            RedisUtil.del(kaptchaKey);

            if (StrUtil.isBlank(adminAuthenticationToken.getImageCode()) || !adminAuthenticationToken.getImageCode().equalsIgnoreCase(kaptcha)) {
                throw new ImageCodeNotMatchExceptionBase("验证码有误");
            }

            try {
                user = yamiUserDetailsService.loadUserByUsername(username);
            } catch (UsernameNotFoundExceptionBase var6) {
                throw new UsernameNotFoundExceptionBase("账号或密码不正确");
            }

            String encodedPassword = user.getPassword();
            String rawPassword = adminAuthenticationToken.getCredentials().toString();

            // 密码不正确
            if (!passwordEncoder.matches(rawPassword, encodedPassword)) {
                throw new BadCredentialsExceptionBase("账号或密码不正确");
            }

            if (!user.isEnabled()) {
                throw new UsernameNotFoundExceptionBase("账号已被锁定,请联系管理员");
            }
             result = new AdminAuthenticationToken(user, adminAuthenticationToken.getCredentials());
             result.setDetails(adminAuthenticationToken.getDetails());
             return result;
        }else if("2".equals(loginType)){
             String flag = smsLogService.checkLoginCode(String.valueOf(adminAuthenticationToken.getPrincipal()),adminAuthenticationToken.getImageCode(), SmsType.LOGINBYSENDSMS);
             if("999".equals(flag)) {
                 String loginName = shopDetailService.getLoginNameByMobile(String.valueOf(adminAuthenticationToken.getPrincipal()));
                 UserDetails user = yamiUserDetailsService.loadUserByUsername(loginName);
                 result = new AdminAuthenticationToken(user, adminAuthenticationToken.getCredentials());
                 result.setDetails(adminAuthenticationToken.getDetails());
             }else if("111".equals(flag)){
                 throw new UsernameNotFoundExceptionBase("验证码错误");
             }else if("222".equals(flag)){
                 throw new UsernameNotFoundExceptionBase("验证码已过期");
             }else if("000".equals(flag)){
                 throw new UsernameNotFoundExceptionBase("验证次数过多");
             }
             return result;
        }else if("3".equals(loginType)){
            UserDetails user = yamiUserDetailsService.loadUserByUsername(username);
            result = new AdminAuthenticationToken(user, adminAuthenticationToken.getCredentials());
            result.setDetails(adminAuthenticationToken.getDetails());
            return result;
        }
        return result;
    }

    private String getStringFromStream(HttpServletRequest req) {
        ServletInputStream is;
        try {
            is = req.getInputStream();
            int nRead = 1;
            int nTotalRead = 0;
            byte[] bytes = new byte[10240];
            while (nRead > 0) {
                nRead = is.read(bytes, nTotalRead, bytes.length - nTotalRead);
                if (nRead > 0) {
                    nTotalRead = nTotalRead + nRead;
                }
            }
            return new String(bytes, 0, nTotalRead, StandardCharsets.UTF_8);
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }

    @Override
    @Autowired
    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        super.setAuthenticationManager(authenticationManager);
    }

    @Override
    @Autowired
    public void setAuthenticationSuccessHandler(AuthenticationSuccessHandler successHandler) {
        super.setAuthenticationSuccessHandler(successHandler);
    }

    @Override
    @Autowired
    public void setAuthenticationFailureHandler(AuthenticationFailureHandler failureHandler) {
        super.setAuthenticationFailureHandler(failureHandler);
    }

}
